home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 11 / Example 11.1 / app.cpp next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  21.3 KB  |  751 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 11.1: Minimap                                    //
  3. // Written by: C. Granberg, 2006                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include "debug.h"
  9. #include "shader.h"
  10. #include "terrain.h"
  11. #include "camera.h"
  12. #include "mouse.h"
  13. #include "player.h"
  14.  
  15. class APPLICATION
  16. {
  17.     public:
  18.         APPLICATION();
  19.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  20.         HRESULT Update(float deltaTime);
  21.         HRESULT Render();
  22.         HRESULT Cleanup();
  23.         HRESULT Quit();
  24.         DWORD FtoDword(float f){return *((DWORD*)&f);}
  25.  
  26.         void AddPlayers(int noPlayers);
  27.         void FogOfWar();
  28.         void UpdateMiniMap();
  29.         void RenderMiniMap(RECT dest);
  30.  
  31.     private:
  32.         IDirect3DDevice9* m_pDevice; 
  33.         TERRAIN m_terrain;
  34.         CAMERA m_camera;
  35.         MOUSE m_mouse;
  36.         std::vector<PLAYER*> m_players;
  37.  
  38.         bool m_wireframe;
  39.         DWORD m_time;
  40.         int m_fps, m_lastFps;
  41.         int m_thisPlayer;
  42.         HWND m_mainWindow;
  43.         ID3DXFont *m_pFont;
  44.         ID3DXLine *m_pLine;
  45.  
  46.         //Fog-of-War variables
  47.         IDirect3DTexture9 *m_pVisibleTexture, *m_pVisitedTexture;
  48.         SHADER m_visitedShader, m_FogOfWarShader;
  49.         ID3DXSprite *m_pSprite;
  50.         bool m_firstFogOfWar;
  51.  
  52.         //Minimap
  53.         IDirect3DTexture9 *m_pMiniMap;
  54.         IDirect3DTexture9 *m_pMiniMapBorder;
  55.         SHADER m_miniMapShader;
  56.         RECT m_miniMapRect;
  57. };
  58.  
  59. D3DRECT SetRect(long x1, long y1, long x2, long y2)
  60. {
  61.     D3DRECT r;
  62.     r.x1 = x1;
  63.     r.y1 = y1;
  64.     r.x2 = x2;
  65.     r.y2 = y2;
  66.     return r;
  67. }
  68.  
  69. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  70. {
  71.     APPLICATION app;
  72.  
  73.     if(FAILED(app.Init(hInstance, 800, 600, true)))return 0;
  74.  
  75.     MSG msg;
  76.     memset(&msg, 0, sizeof(MSG));
  77.     int startTime = timeGetTime(); 
  78.  
  79.     while(msg.message != WM_QUIT)
  80.     {
  81.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  82.         {
  83.             ::TranslateMessage(&msg);
  84.             ::DispatchMessage(&msg);
  85.         }
  86.         else
  87.         {    
  88.             int t = timeGetTime();
  89.             float deltaTime = (t - startTime)*0.001f;
  90.  
  91.             app.Update(deltaTime);
  92.             app.Render();
  93.  
  94.             startTime = t;
  95.         }
  96.     }
  97.  
  98.     app.Cleanup();
  99.  
  100.     return msg.wParam;
  101. }
  102.  
  103. APPLICATION::APPLICATION()
  104. {
  105.     m_pDevice = NULL; 
  106.     m_mainWindow = 0;
  107.     m_wireframe = false;
  108.     srand(GetTickCount());
  109.     m_fps = m_lastFps = m_thisPlayer = 0;
  110.     m_time = GetTickCount();
  111.     m_pLine = NULL;
  112.     m_firstFogOfWar = true;
  113.  
  114.     m_pVisibleTexture = m_pVisitedTexture = m_pMiniMap = NULL;
  115.     m_pMiniMapBorder = NULL;
  116. }
  117.  
  118. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  119. {
  120.     debug.Print("Application initiated");
  121.  
  122.     //Create Window Class
  123.     WNDCLASS wc;
  124.     memset(&wc, 0, sizeof(WNDCLASS));
  125.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  126.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  127.     wc.hInstance     = hInstance;
  128.     wc.lpszClassName = "D3DWND";
  129.  
  130.     //Register Class and Create new Window
  131.     RegisterClass(&wc);
  132.     m_mainWindow = CreateWindow("D3DWND", "Example 11.1: Minimap", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  133.     SetCursor(NULL);
  134.     ShowWindow(m_mainWindow, SW_SHOW);
  135.     UpdateWindow(m_mainWindow);
  136.  
  137.     //Create IDirect3D9 Interface
  138.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  139.  
  140.     if(d3d9 == NULL)
  141.     {
  142.         debug.Print("Direct3DCreate9() - FAILED");
  143.         return E_FAIL;
  144.     }
  145.  
  146.     //Check that the m_pDevice supports what we need from it
  147.     D3DCAPS9 caps;
  148.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  149.  
  150.     //Hardware Vertex Processing or not?
  151.     int vp = 0;
  152.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  153.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  154.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  155.  
  156.     //Check vertex & pixelshader versions
  157.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  158.     {
  159.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  160.     }
  161.  
  162.     //Set D3DPRESENT_PARAMETERS
  163.     D3DPRESENT_PARAMETERS d3dpp;
  164.     d3dpp.BackBufferWidth            = width;
  165.     d3dpp.BackBufferHeight           = height;
  166.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  167.     d3dpp.BackBufferCount            = 1;
  168.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  169.     d3dpp.MultiSampleQuality         = 0;
  170.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  171.     d3dpp.hDeviceWindow              = m_mainWindow;
  172.     d3dpp.Windowed                   = windowed;
  173.     d3dpp.EnableAutoDepthStencil     = true; 
  174.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  175.     d3dpp.Flags                      = 0;
  176.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  177.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  178.  
  179.     //Create the IDirect3DDevice9
  180.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  181.                                  vp, &d3dpp, &m_pDevice)))
  182.     {
  183.         debug.Print("Failed to create IDirect3DDevice9");
  184.         return E_FAIL;
  185.     }
  186.  
  187.     //Release IDirect3D9 interface
  188.     d3d9->Release();
  189.  
  190.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  191.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  192.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  193.  
  194.     LoadObjectResources(m_pDevice);
  195.     LoadMapObjectResources(m_pDevice);
  196.     LoadUnitResources(m_pDevice);
  197.     LoadBuildingResources(m_pDevice);
  198.     LoadPlayerResources(m_pDevice);
  199.  
  200.     m_mouse.InitMouse(m_pDevice, m_mainWindow);
  201.  
  202.     m_camera.Init(m_pDevice);
  203.     m_camera.m_fov = 0.6f;
  204.     m_camera.m_radius = 50.0f;
  205.  
  206.     D3DXCreateLine(m_pDevice, &m_pLine);
  207.  
  208.     //Set sampler state
  209.     for(int i=0;i<8;i++)
  210.     {
  211.         m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  212.         m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  213.         m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  214.     }
  215.  
  216.     //Create Fog-of-war textures
  217.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pVisibleTexture, NULL)))debug.Print("Failed to create texture: m_pVisibleTexture");
  218.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pVisitedTexture, NULL)))debug.Print("Failed to create texture: m_pVisitedTexture");
  219.  
  220.     //Fog-of-war Shaders
  221.     m_visitedShader.Init(m_pDevice, "shaders/visited.ps", PIXEL_SHADER);
  222.     m_FogOfWarShader.Init(m_pDevice, "shaders/FogOfWar.ps", PIXEL_SHADER);
  223.     m_firstFogOfWar = true;
  224.  
  225.     //Create Minimap
  226.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pMiniMap, NULL)))debug.Print("Failed to create texture: miniMap");
  227.     if(FAILED(D3DXCreateTextureFromFile(m_pDevice, "textures/minimap.dds", &m_pMiniMapBorder)))debug.Print("Could not load minimap.dds");
  228.     m_miniMapShader.Init(m_pDevice, "shaders/minimap.ps", PIXEL_SHADER);
  229.     RECT r = {611, 9, 791, 189};
  230.     m_miniMapRect = r;
  231.  
  232.     //Sprite 
  233.     D3DXCreateSprite(m_pDevice, &m_pSprite);
  234.  
  235.     //Init Terrain
  236.     m_terrain.Init(m_pDevice, INTPOINT(150,150));
  237.  
  238.     //Add Players
  239.     AddPlayers(4);
  240.     
  241.     return S_OK;
  242. }
  243.  
  244. HRESULT APPLICATION::Update(float deltaTime)
  245. {        
  246.     //Update Players
  247.     for(int i=0;i<m_players.size();i++)
  248.         if(m_players[i] != NULL)
  249.             m_players[i]->UpdateMapObjects(deltaTime);
  250.  
  251.     //Update Fog-of-War
  252.     FogOfWar();
  253.  
  254.     //Control camera
  255.     m_camera.Update(m_mouse, m_terrain, deltaTime);
  256.     m_mouse.Update(m_terrain);
  257.  
  258.     //Update SightMatrices & visible variables
  259.     if(m_terrain.m_updateSight)
  260.     {
  261.         m_terrain.m_updateSight = false;
  262.  
  263.         if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  264.             m_terrain.UpdateSightMatrices(m_players[m_thisPlayer]->m_mapObjects);
  265.  
  266.         for(int i=0;i<m_players.size();i++)
  267.             if(m_players[i] != NULL)
  268.                 m_players[i]->IsMapObjectsVisible();
  269.  
  270.         //Update Minimap        
  271.         UpdateMiniMap();
  272.     }
  273.  
  274.     //Order units of m_thisPlayer's team around & Order other players units around randomly
  275.     for(int i=0;i<m_players.size();i++)
  276.         if(m_players[i] != NULL)
  277.             m_players[i]->UnitOrders(m_mouse, i == m_thisPlayer);
  278.  
  279.     //Keyboard input
  280.     if(KEYDOWN('W'))
  281.     {
  282.         m_wireframe = !m_wireframe;
  283.         Sleep(300);
  284.     }
  285.     else if(KEYDOWN(VK_SPACE))
  286.     {
  287.         m_terrain.GenerateRandomTerrain(15);
  288.         AddPlayers(4);
  289.     }
  290.     else if(KEYDOWN(VK_ESCAPE))
  291.     {
  292.         Quit();
  293.     }
  294.  
  295.     return S_OK;
  296. }    
  297.  
  298. HRESULT APPLICATION::Render()
  299. {
  300.     // Clear the viewport
  301.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  302.  
  303.     //FPS Calculation
  304.     m_fps++;
  305.     if(GetTickCount() - m_time > 1000)
  306.     {
  307.         m_lastFps = m_fps;
  308.         m_fps = 0;
  309.         m_time = GetTickCount();
  310.     }
  311.  
  312.     // Begin the scene 
  313.     if(SUCCEEDED(m_pDevice->BeginScene()))
  314.     {
  315.         if(m_wireframe)m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);    
  316.         else m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  317.  
  318.         m_terrain.Render(m_camera);
  319.  
  320.         for(int i=0;i<m_players.size();i++)
  321.             if(m_players[i] != NULL)
  322.                 m_players[i]->RenderMapObjects(m_camera);
  323.  
  324.         //Select units
  325.         if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  326.         {
  327.             m_players[m_thisPlayer]->PaintSelectedMapObjects(m_camera);
  328.             m_players[m_thisPlayer]->Select(m_mouse);
  329.         }
  330.  
  331.         //Render Minimap
  332.         RenderMiniMap(m_miniMapRect);
  333.  
  334.         m_mouse.Paint();
  335.  
  336.         RECT r[] = {{10, 10, 0, 0}, {520, 10, 0, 0}};
  337.         m_pFont->DrawText(NULL, "Space: Randomize Terrain", -1, &r[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffffffff);
  338.  
  339.         //FPS
  340.         char number[50];
  341.         std::string text = "FPS: ";
  342.         text += _itoa(m_lastFps, number, 10);
  343.         m_pFont->DrawText(NULL, text.c_str(), -1, &r[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffffffff);
  344.  
  345.         // End the scene.
  346.         m_pDevice->EndScene();
  347.         m_pDevice->Present(0, 0, 0, 0);
  348.     }
  349.  
  350.     return S_OK;
  351. }
  352.  
  353. HRESULT APPLICATION::Cleanup()
  354. {
  355.     try
  356.     {
  357.         m_terrain.Release();
  358.  
  359.         UnloadObjectResources();
  360.         UnloadMapObjectResources();
  361.         UnloadUnitResources();
  362.         UnloadBuildingResources();
  363.         UnloadPlayerResources();
  364.  
  365.         if(m_pVisibleTexture)m_pVisibleTexture->Release();
  366.         if(m_pVisitedTexture)m_pVisitedTexture->Release();
  367.         if(m_pMiniMap)m_pMiniMap->Release();
  368.         if(m_pMiniMapBorder)m_pMiniMapBorder->Release();
  369.  
  370.         for(int i=0;i<m_players.size();i++)
  371.             if(m_players[i] != NULL)
  372.                 delete m_players[i];
  373.         m_players.clear();
  374.  
  375.         m_pFont->Release();
  376.         m_pLine->Release();
  377.         m_pSprite->Release();
  378.         m_pDevice->Release();
  379.  
  380.         debug.Print("Application terminated");
  381.     }
  382.     catch(...){}
  383.  
  384.     return S_OK;
  385. }
  386.  
  387. HRESULT APPLICATION::Quit()
  388. {
  389.     ::DestroyWindow(m_mainWindow);
  390.     ::PostQuitMessage(0);
  391.     return S_OK;
  392. }
  393.  
  394. void APPLICATION::AddPlayers(int noPlayers)
  395. {
  396.     m_thisPlayer = 0;
  397.  
  398.     for(int i=0;i<m_players.size();i++)
  399.         if(m_players[i] != NULL)
  400.             delete m_players[i];
  401.     m_players.clear();
  402.  
  403.     INTPOINT startLocations[] = {INTPOINT(30,30), INTPOINT(120,30), INTPOINT(30,120), INTPOINT(120,120)};
  404.     D3DXVECTOR4 teamCols[] = {D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f), D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f),
  405.                               D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f), D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f)};
  406.     
  407.     if(noPlayers < 2)noPlayers = 2;
  408.     if(noPlayers > 4)noPlayers = 4;
  409.  
  410.     for(int i=0;i<noPlayers;i++)
  411.     {
  412.         m_terrain.Progress("Creating Players", i / (float)noPlayers);
  413.         m_players.push_back(new PLAYER(i, teamCols[i], startLocations[i], &m_terrain, m_pDevice));    
  414.     }
  415.  
  416.     //Center m_camera focus on the team...
  417.     m_camera.m_focus = m_terrain.GetWorldPos(m_players[m_thisPlayer]->GetCenter());
  418. }
  419.  
  420. void APPLICATION::FogOfWar()
  421. {
  422.     try
  423.     {
  424.         if(m_pVisibleTexture == NULL || m_pVisitedTexture == NULL)return;
  425.         
  426.         //Set orthogonal rendering view & projection
  427.         m_terrain.SetOrthogonalView();
  428.  
  429.         //Retrieve the surface of the back buffer
  430.         IDirect3DSurface9 *backSurface = NULL;
  431.         m_pDevice->GetRenderTarget(0, &backSurface);
  432.  
  433.         //Render the Visible Texture here...
  434.         {
  435.             //Set texture stages and Renderstates
  436.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  437.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
  438.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_ADD);
  439.             m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  440.             m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
  441.             m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
  442.  
  443.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
  444.             m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  445.             m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  446.             m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTALPHA);
  447.             
  448.             //Get the surface of the m_pVisibleTexture
  449.             IDirect3DSurface9 *visibleSurface = NULL;            
  450.             m_pVisibleTexture->GetSurfaceLevel(0, &visibleSurface);            
  451.  
  452.             //Set render target to the visible surface
  453.             m_pDevice->SetRenderTarget(0, visibleSurface);
  454.  
  455.             //Clear render target to black
  456.             m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  457.  
  458.             m_pDevice->BeginScene();
  459.  
  460.             //Render the sightTexture for all map objects in m_thisPlayer.
  461.             if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  462.                 for(int u=0;u<m_players[m_thisPlayer]->m_mapObjects.size();u++)
  463.                     if(m_players[m_thisPlayer]->m_mapObjects[u] != NULL)
  464.                         m_players[m_thisPlayer]->m_mapObjects[u]->RenderSightMesh();
  465.  
  466.             m_pDevice->EndScene();
  467.  
  468.             //Restore renderstates etc.
  469.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  470.             m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  471.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  472.             m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  473.  
  474.             //Release visible surface
  475.             visibleSurface->Release();
  476.         }
  477.  
  478.         //Render the Visited Texture here...
  479.         {
  480.             IDirect3DSurface9 *visitedSurface = NULL;
  481.             m_pVisitedTexture->GetSurfaceLevel(0, &visitedSurface);
  482.  
  483.             //Render to the visted texture
  484.             m_pDevice->SetRenderTarget(0, visitedSurface);
  485.             if(m_firstFogOfWar)
  486.             {
  487.                 m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  488.                 m_firstFogOfWar = false;
  489.             }
  490.  
  491.             m_pDevice->BeginScene();
  492.             m_pDevice->SetTexture(0, m_pVisibleTexture);
  493.             m_pDevice->SetTexture(1, m_pVisitedTexture);
  494.  
  495.             m_pSprite->Begin(0);
  496.             m_visitedShader.Begin();
  497.             m_pSprite->Draw(m_pVisibleTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  498.             m_pSprite->End();
  499.             m_visitedShader.End();
  500.  
  501.             m_pDevice->EndScene();
  502.         
  503.             //Release visited surface
  504.             visitedSurface->Release();
  505.         }
  506.  
  507.         //Render the final m_pFogOfWarTexture
  508.         {
  509.             //Get and set surface of the m_pFogOfWarTexture...
  510.             IDirect3DSurface9 *FogOfWarSurface = NULL;
  511.             m_terrain.m_pFogOfWarTexture->GetSurfaceLevel(0, &FogOfWarSurface);
  512.             m_pDevice->SetRenderTarget(0, FogOfWarSurface);
  513.  
  514.             m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  515.             m_pDevice->BeginScene();
  516.  
  517.             //Set Textures
  518.             m_pDevice->SetTexture(0, m_pVisibleTexture);
  519.             m_pDevice->SetTexture(1, m_pVisitedTexture);
  520.             m_pDevice->SetTexture(2, m_terrain.m_pLightMap);
  521.  
  522.             //Draw to the Fog-of-War texture
  523.             m_pSprite->Begin(0);
  524.             m_FogOfWarShader.Begin();
  525.             m_pSprite->Draw(m_pVisibleTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  526.             m_pSprite->End();
  527.             m_FogOfWarShader.End();
  528.  
  529.             m_pDevice->EndScene();
  530.  
  531.             //Release fog of war surface
  532.             FogOfWarSurface->Release();
  533.         }
  534.  
  535.         //Reset render target to back buffer
  536.         m_pDevice->SetRenderTarget(0, backSurface);
  537.         backSurface->Release();        
  538.     }
  539.     catch(...)
  540.     {
  541.         debug.Print("Error in APPLICATION::FogOfWar()");
  542.     }
  543. }
  544.  
  545. void APPLICATION::UpdateMiniMap()
  546. {
  547.     //Retrieve the surface of the back buffer
  548.     IDirect3DSurface9 *backSurface = NULL;
  549.     m_pDevice->GetRenderTarget(0, &backSurface);
  550.  
  551.     //Get and set surface of the m_pFogOfWarTexture...
  552.     IDirect3DSurface9 *minimapSurface = NULL;
  553.     m_pMiniMap->GetSurfaceLevel(0, &minimapSurface);
  554.     m_pDevice->SetRenderTarget(0, minimapSurface);
  555.  
  556.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  557.     m_pDevice->BeginScene();
  558.  
  559.     //Set Textures
  560.     m_pDevice->SetTexture(0, m_terrain.m_pLandScape);
  561.     m_pDevice->SetTexture(1, m_terrain.m_pFogOfWarTexture);
  562.  
  563.     //Draw to the minimap texture
  564.     m_pSprite->Begin(0);
  565.     m_miniMapShader.Begin();
  566.     m_pSprite->Draw(m_terrain.m_pLandScape, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  567.     m_pSprite->End();
  568.     m_miniMapShader.End();
  569.  
  570.     m_pDevice->EndScene();
  571.  
  572.     //Draw units and buildings in the player team color
  573.     for(int p=0;p<m_players.size();p++)
  574.         if(m_players[p] != NULL)
  575.         {
  576.             std::vector<D3DRECT> rects;
  577.  
  578.             //Get rectangles in "Minimap Space"
  579.             for(int m=0;m<m_players[p]->m_mapObjects.size();m++)
  580.                 if(m_players[p]->m_mapObjects[m] != NULL)
  581.                     if(!m_players[p]->m_mapObjects[m]->m_isBuilding)
  582.                     {
  583.                         INTPOINT mappos = m_players[p]->m_mapObjects[m]->m_mappos;
  584.  
  585.                         //Only add units standing on visible tiles
  586.                         if(m_terrain.m_pVisibleTiles[mappos.x + mappos.y * m_terrain.m_size.x])
  587.                         {
  588.                             INTPOINT pos(256.0f * (mappos.x / (float)m_terrain.m_size.x), 
  589.                                          256.0f * (mappos.y / (float)m_terrain.m_size.y));
  590.  
  591.                             rects.push_back(SetRect(pos.x - 1, pos.y - 1, 
  592.                                                     pos.x + 2, pos.y + 2));
  593.                         }
  594.                     }
  595.                     else 
  596.                     {
  597.                         RECT r = m_players[p]->m_mapObjects[m]->GetMapRect(0);
  598.  
  599.                         //Add only those parts of the buildings standing on visited tiles
  600.                         for(int y=r.top;y<=r.bottom;y++)
  601.                             for(int x=r.left;x<=r.right;x++)
  602.                                 if(m_terrain.m_pVisitedTiles[x + y * m_terrain.m_size.x])
  603.                                 {
  604.                                     INTPOINT pos(256.0f * (x / (float)m_terrain.m_size.x), 
  605.                                                  256.0f * (y / (float)m_terrain.m_size.y));
  606.  
  607.                                     rects.push_back(SetRect(pos.x - 1, pos.y - 1, 
  608.                                                             pos.x + 2, pos.y + 2));
  609.                                 }
  610.                     }
  611.  
  612.             //Clear rectangles using the team color
  613.             if(!rects.empty())
  614.             {
  615.                 D3DXCOLOR c = D3DCOLOR_XRGB((int)(m_players[p]->m_teamColor.x * 255),
  616.                                             (int)(m_players[p]->m_teamColor.y * 255),
  617.                                             (int)(m_players[p]->m_teamColor.z * 255));
  618.                 
  619.                 m_pDevice->Clear(rects.size(), &rects[0], D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, c, 1.0f, 0);
  620.             }
  621.         }
  622.  
  623.     //Reset render target to back buffer
  624.     m_pDevice->SetRenderTarget(0, backSurface);
  625.  
  626.     //Release surfaces
  627.     backSurface->Release();
  628.     minimapSurface->Release();
  629.  
  630. }
  631.  
  632. void APPLICATION::RenderMiniMap(RECT dest)
  633. {
  634.     float width = dest.right - dest.left;
  635.     float height = dest.bottom - dest.top;
  636.  
  637.     D3DXVECTOR2 scale = D3DXVECTOR2(width / 256.0f, 
  638.                                     height / 256.0f);
  639.     D3DXMATRIX sca;
  640.     D3DXMatrixScaling(&sca, scale.x, scale.y, 1.0f);
  641.     m_pSprite->SetTransform(&sca);
  642.  
  643.     m_pSprite->Begin(0);
  644.     m_pSprite->Draw(m_pMiniMap, NULL, NULL, &D3DXVECTOR3(dest.left / scale.x, dest.top / scale.y, 0.0f), 0xffffffff);
  645.     m_pSprite->End();
  646.  
  647.     D3DXMatrixIdentity(&sca);
  648.     m_pSprite->SetTransform(&sca);
  649.  
  650.     //Move camera using minimap
  651.     if(m_mouse.PressInRect(dest))
  652.     {
  653.         int x = ((m_mouse.x - dest.left) / width) * m_terrain.m_size.x;
  654.         int y = ((m_mouse.y - dest.top) / height) * m_terrain.m_size.y;
  655.  
  656.         m_camera.m_focus = m_terrain.GetWorldPos(INTPOINT(x, y));
  657.     }
  658.  
  659.     //Calculate m_camera frustum viewpoints
  660.     D3DXMATRIX view, proj, viewInverse;
  661.  
  662.     view = m_camera.GetViewMatrix();
  663.     proj = m_camera.GetProjectionMatrix();
  664.     
  665.     //fov_x & fov_y Determines the size of the frustum representation
  666.     float screenRatio = proj(0,0) / proj(1,1);
  667.     float fov_x = 0.4f;
  668.     float fov_y = fov_x * screenRatio;
  669.     
  670.     //Initialize the four rays
  671.     D3DXVECTOR3 org = D3DXVECTOR3(0.0f, 0.0f, 0.0f);    //Same origin
  672.  
  673.     //Four different directions
  674.     D3DXVECTOR3 dir[4] = {D3DXVECTOR3(-fov_x, fov_y, 1.0f),    
  675.                            D3DXVECTOR3(fov_x, fov_y, 1.0f),
  676.                           D3DXVECTOR3(fov_x, -fov_y, 1.0f),
  677.                           D3DXVECTOR3(-fov_x, -fov_y, 1.0f)};
  678.  
  679.     //Our resulting minimap coordinates
  680.     D3DXVECTOR2 points[5];
  681.  
  682.     //View matrix inverse
  683.     D3DXMatrixInverse(&viewInverse, 0, &view);
  684.     D3DXVec3TransformCoord(&org, &org, &viewInverse);
  685.  
  686.     //Ground plane
  687.     D3DXPLANE plane;
  688.     D3DXPlaneFromPointNormal(&plane, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
  689.  
  690.     bool ok = true;
  691.  
  692.     //check where each ray intersects with the ground plane
  693.     for(int i=0;i<4 && ok;i++)
  694.     {
  695.         //Transform ray direction
  696.         D3DXVec3TransformNormal(&dir[i], &dir[i], &viewInverse);
  697.         D3DXVec3Normalize(&dir[i], &dir[i]);
  698.         dir[i] *= 1000.0f;
  699.  
  700.         //Find intersection point
  701.         D3DXVECTOR3 hit;
  702.         if(D3DXPlaneIntersectLine(&hit, &plane, &org, &dir[i]) == NULL)
  703.             ok = false;
  704.  
  705.         //Make sure the intersection point is on the positive side of the near plane
  706.         D3DXPLANE n = m_camera.m_frustum[4];
  707.         float distance = n.a * hit.x + n.b * hit.y + n.c * hit.z + n.d;
  708.         if(distance < 0.0f)ok = false;
  709.  
  710.         //Convert the intersection point to a minimap coordinate
  711.         if(ok)
  712.         {
  713.             points[i].x = (hit.x / (float)m_terrain.m_size.x) * width;
  714.             points[i].y = (-hit.z / (float)m_terrain.m_size.y) * height;
  715.         }
  716.     }
  717.  
  718.     //Set the end point to equal the starting point
  719.     points[4] = points[0];
  720.  
  721.     //Set viewport to destination rectangle only...
  722.     D3DVIEWPORT9 v1, v2;
  723.  
  724.     v1.X = dest.left;
  725.     v1.Y = dest.top;
  726.     v1.Width = width;
  727.     v1.Height = height;
  728.     v1.MinZ = 0.0f;
  729.     v1.MaxZ = 1.0f;
  730.  
  731.     m_pDevice->GetViewport(&v2);
  732.     m_pDevice->SetViewport(&v1);
  733.  
  734.     //Draw camera frustum in the minimap
  735.     if(ok)
  736.     {
  737.         m_pLine->SetWidth(1.0f);
  738.         m_pLine->SetAntialias(true);
  739.         m_pLine->Begin();
  740.         m_pLine->Draw(&points[0], 5, 0x44ffffff);
  741.         m_pLine->End();
  742.     }
  743.  
  744.     //Reset viewport
  745.     m_pDevice->SetViewport(&v2);
  746.  
  747.     //Draw minimap border
  748.     m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
  749.     m_pSprite->Draw(m_pMiniMapBorder, NULL, NULL, &D3DXVECTOR3(v2.Width - 256, 0.0f, 0.0f), 0xffffffff);
  750.     m_pSprite->End();
  751. }